package game.coord;

import game.Logger;
import game.games.carcassonne.IterablePoint;

import java.awt.Dimension;
import java.awt.Point;

public class MapGenerator
{
    public static Point getRight(Point position, Dimension maxSize)
    {
        // RIGHT:
        Point RIGHT = new Point(position.x + 1, position.y);
        if (RIGHT.getX() >= maxSize.width)
        {
            RIGHT.move(0, RIGHT.y);
        }
        return RIGHT;
    }
    
    public static Point getBottom(Point position, Dimension maxSize)
    {
        // BOTTOM:
        Point BOTTOM = new Point(position.x, position.y + 1);
        if (BOTTOM.getY() >= maxSize.height)
        {
            BOTTOM.move(BOTTOM.x, 0);
        }
        return BOTTOM;
    }
    
    public static Point getLeft(Point position, Dimension maxSize)
    {
        // LEFT:
        Point LEFT = new Point(position.x - 1, position.y);
        if (LEFT.getX() < 0)
        {
            LEFT.move(maxSize.width - 1, LEFT.y);
        }
        return LEFT;
    }
    
    public static Point getTop(Point position, Dimension maxSize)
    {
        // TOP:
        Point TOP = new Point(position.x, position.y - 1);
        if (TOP.getY() < 0)
        {
            TOP.move(TOP.x, maxSize.height - 1);
        }
        return TOP;
    }
    
    public static Point getBottomLeft(Point position, Dimension maxSize)
    {
        // BOTTOMLEFT:
        Point BOTTOMLEFT = new Point(getLeft(position, maxSize).x, getBottom(position, maxSize).y);
        return BOTTOMLEFT;
    }
    
    public static Point getBottomRight(Point position, Dimension maxSize)
    {
        // BOTTOMRIGHT:
        Point BOTTOMRIGHT = new Point(getRight(position, maxSize).x, getBottom(position, maxSize).y);
        return BOTTOMRIGHT;
    }
    
    public static Point getTopLeft(Point position, Dimension maxSize)
    {
        // TOPLEFT:
        Point TOPLEFT = new Point(getLeft(position, maxSize).x, getTop(position, maxSize).y);
        return TOPLEFT;
    }
    
    public static Point getTopRight(Point position, Dimension maxSize)
    {
        // TOPRIGHT:
        Point TOPRIGHT = new Point(getRight(position, maxSize).x, getTop(position, maxSize).y);
        return TOPRIGHT;
    }
    
    public static <TYPE> MultiArrayContainer<TYPE> generateList(Dimension size, Class<TYPE> typeClass)
    {
        Logger.log("GENERATE LIST (" + size + " x " + typeClass + ")");
        MultiArrayContainer<TYPE> list = new MultiArrayContainer<TYPE>(size);
        for (int y = 0; y < size.height; y++)
        {
            for (int x = 0; x < size.width; x++)
            {
                TYPE instance = null;
                try
                {
                    instance = typeClass.newInstance();
                }
                catch (InstantiationException | IllegalAccessException ex)
                {
                    ex.printStackTrace();
                }
                list.setValue(new Point(x, y), instance);
            }
        }
        return list;
    }
    
    public static <TYPE> MultiArrayContainer<TYPE> generateList(Dimension size, TYPE defaultValue)
    {
        Logger.log("GENERATE LIST (" + size + " x " + defaultValue + ")");
        MultiArrayContainer<TYPE> list = new MultiArrayContainer<TYPE>(size);
        for (int y = 0; y < size.height; y++)
        {
            for (int x = 0; x < size.width; x++)
            {
                TYPE instance = defaultValue;
                list.setValue(new Point(x, y), instance);
            }
        }
        return list;
    }
    
    public static <TYPE extends MooreCell<TYPE>> MultiArrayContainer<TYPE> generateMooreMap(Dimension size, Class<TYPE> cellClass)
    {
        MultiArrayContainer<TYPE> list = generateList(size, cellClass);
        rebuildMooreMap(list);
        return list;
    }
    
    public static <TYPE extends MooreCell<TYPE>> MultiArrayContainer<TYPE> generateMooreMap(Dimension size, TYPE defaultValue)
    {
        MultiArrayContainer<TYPE> list = generateList(size, defaultValue);
        rebuildMooreMap(list);
        return list;
    }
    
    public static <TYPE extends MooreCell<TYPE>> void rebuildMooreMap(MultiArrayContainer<TYPE> list)
    {
        for (IterablePoint<TYPE> i = list.getIterator(); i.hasNext();)
        {
            Point position = i.getCurrentPoint();
            TYPE cell = i.next();
            cell.setRight(list.getValue(getRight(position, list.getSize())));
            cell.setBottom(list.getValue( getBottom(position, list.getSize())));
            cell.setLeft(list.getValue( getLeft(position, list.getSize())));
            cell.setTop(list.getValue( getTop(position, list.getSize())));
            cell.setBottomLeft(list.getValue( getBottomLeft(position, list.getSize())));
            cell.setBottomRight(list.getValue( getBottomRight(position, list.getSize())));
            cell.setTopLeft(list.getValue( getTopLeft(position, list.getSize())));
            cell.setTopRight(list.getValue( getTopRight(position, list.getSize())));
        }
    }
    
    public static <TYPE extends VonNeumannCell<TYPE>> MultiArrayContainer<TYPE> generateVonNeumannMap(Dimension size, Class<TYPE> cellClass)
    {
        MultiArrayContainer<TYPE> list = generateList(size, cellClass);
        rebuildVonNeumannMap(list);
        return list;
    }
    
    public static <TYPE extends VonNeumannCell<TYPE>> MultiArrayContainer<TYPE> generateVonNeumannMap(Dimension size, TYPE defaultValue)
    {
        MultiArrayContainer<TYPE> list = generateList(size, defaultValue);
        rebuildVonNeumannMap(list);
        return list;
    }
    
    public static <TYPE extends VonNeumannCell<TYPE>> void rebuildVonNeumannMap(MultiArrayContainer<TYPE> list)
    {
        for (IterablePoint<TYPE> i = list.getIterator(); i.hasNext();)
        {
            Point position = i.getCurrentPoint();
            TYPE cell = i.next();
            cell.setRight(list.getValue(getRight(position, list.getSize())));
            cell.setBottom(list.getValue(getBottom(position, list.getSize())));
            cell.setLeft(list.getValue(getLeft(position, list.getSize())));
            cell.setTop(list.getValue(getTop(position, list.getSize())));
        }
    }
}
